home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / cap / tools / awk.c next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  19.4 KB  |  787 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17.  
  18. /*
  19.  *  Kurt Akeley
  20.  *  4 June 1987
  21.  * 
  22.  *  Utility routines to implement awk programs in C
  23.  *
  24.  *  Changes from version 1:
  25.  *
  26.  *  1.    All references to 'group' are changed to 'array'.
  27.  *  2.    It is no longer necessary to specify maximum 'array' size.
  28.  *    Rather, arrays grow as necessary.
  29.  *  3.    Added POINTER type (in addition to INDEX,INT,FLOAT,STRING).
  30.  *  4.    Increased all maximum values.
  31.  *  5.    Index() renamed sindex().
  32.  *  6.    Command line FS specification added.
  33.  *  7.    4/12/89 KBA - changed getpointer to return 0 if not found.
  34.  *              getstring still returns "" in this case.
  35.  *  8.    5/6/89 KBA - changed argv treatment to ignore null fields
  36.  *  9.    11/91 KBA - closed files immediately, rather than when the
  37.  *            next file is opened.
  38.  * 10.    11/91 KBA - added numeric keys
  39.  * 11.    11/91 KBA - prefixed all visible routine names with "awk"
  40.  *            words in names now capitalized in GL 5.0 manner
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <awk.h>
  45.  
  46. #define NOTFATAL    0
  47. #define AWKFATAL    1
  48.  
  49. #define VERSION        "3.0"
  50. #define DATE        "18 November 1991"
  51.  
  52. #define MAXARG        0x100
  53. #define MAXARGLEN    0x1000
  54. #define MAXSTR        0x100
  55. #define MAXKEYLEN    MAXSTR
  56. #define MAXARRAY    0x100
  57. #define INITIALSIZE    0x100
  58. #define REMAIN(i)    (6*(i)) / 10 - 1;    
  59.  
  60. /*
  61.  * Visible global variable declarations
  62.  */
  63. int awkNF;            /* number of fields in current line */
  64. int awkNL;            /* line number in currently open file */
  65. int awkNR;            /* number of current record - all files */
  66. int awkFS;            /* field separator character */
  67. int awkRS;            /* record separator character */
  68. char awkFILENAME[MAXSTR+2];    /* filename of currently open file */
  69. char *awkARG[MAXARG+2];        /* pointers to argument strings */
  70.  
  71. /*
  72.  * Internal global variable declarations
  73.  */
  74. static char line[MAXARGLEN+2];
  75. static char args[MAXARGLEN+2];
  76. static FILE *infile = 0;
  77. static int ARGC;
  78. static char **ARGV;
  79. static char es[200];
  80. static hashval[128];
  81. static int DEBUG;
  82. static int STAT;
  83. static int awkinited = 0;
  84. static int filecount = 0;
  85.  
  86. /*
  87.  * Internal diagnostic variable declarations
  88.  */
  89. #ifdef METER
  90. static int access, search, storage;
  91. static AwkArray *arraylist[MAXARRAY];
  92. static int arraycount = 0;
  93. #endif
  94.  
  95. /*
  96.  * Internal procedure and function definitions
  97.  */
  98. static void awkopen (char *s);
  99. static int awkopennext(void);
  100. static void awkclose (void);
  101. static void error (int class, char *s);
  102. static void expandarray (AwkArray *array);
  103. static int hash (AwkArray *array, register char *key);
  104. static AwkArray *newarray (AwkArray *array);
  105. static char *newstring (char *s);
  106.  
  107. /*
  108.  * Diagnostic procedure and function definitions
  109.  */
  110. void _awk_seearray (AwkArray *array);
  111. void _awk_statall (void);
  112.  
  113. /*
  114.  * Visible procedures and functions
  115.  */
  116.  
  117. void awkAddFloat (AwkArray *array, char *key, float f) {
  118. #ifdef CAREFUL
  119.     if (awkinited == 0)
  120.     error (AWKFATAL, "awkAddFloat called prior to awkInit");
  121.     if (array == 0)
  122.     error (AWKFATAL, "awkAddFloat: tried to access an uninitialized array");
  123.     if (array->fval == 0) {
  124.     sprintf (es, "tried to add a float to %s AwkArray %s",
  125.         array->ival ? "AWK_INT" :
  126.         (array->string ? "AWK_STRING" : "AWK_INDEX"),
  127.         array->name);
  128.     error (NOTFATAL, es);
  129.     return;
  130.     }
  131. #endif
  132.     array->fval[awkAddIndex (array, key)] = f;
  133. }
  134.  
  135. int awkAddIndex (register AwkArray *array, register char *key) {
  136.     /* add a new key to the indexed table.  return the index  */
  137.     register index;
  138.     register maxindex;
  139.     if (array->remain == 0)
  140.     expandarray (array);
  141.     index = hash (array, key);
  142.     maxindex = array->max - 1;
  143. #ifdef METER
  144.     array->access += 1;
  145.     access += 1;
  146. #endif
  147.     while (TRUE) {
  148.     if (!(array->key[index])) {
  149.         array->key[index] = newstring (key);
  150.         array->remain -= 1;
  151.         break;
  152.     }
  153.     else if (awkStrSame (key, array->key[index]))
  154.         break;
  155.     else {
  156. #ifdef METER
  157.         array->search += 1;
  158.         search += 1;
  159. #endif
  160.         if (index == maxindex)
  161.         index = 0;
  162.         else
  163.         index += 1;
  164.     }
  165.     }
  166.     return index;
  167. }
  168.  
  169. void awkAddInt (AwkArray *array, char *key, int i) {
  170. #ifdef CAREFUL
  171.     if (awkinited == 0)
  172.     error (AWKFATAL, "awkAddInt called prior to awkinit");
  173.     if (array == 0)
  174.     error (AWKFATAL, "awkAddInt: tried to access an uninitialized array");
  175.     if (array->ival == 0) {
  176.     sprintf (es, "tried to add an integer to %s AwkArray %s",
  177.         array->fval ? "AWK_FLOAT" :
  178.         (array->string ? "AWK_STRING" : "AWK_INDEX"),
  179.         array->name);
  180.     error (NOTFATAL, es);
  181.     return;
  182.     }
  183. #endif
  184.     array->ival[awkAddIndex (array, key)] = i;
  185. }
  186.  
  187. void awkAddPointer (AwkArray *array, char *key, void *p) {
  188. #ifdef CAREFUL
  189.     if (awkinited == 0)
  190.     error (AWKFATAL, "awkAddPointer called prior to awkInit");
  191.     if (array == 0)
  192.     error (AWKFATAL,
  193.         "awkAddPointer: tried to access an uninitialized array");
  194.     if (array->string == 0) {
  195.     sprintf (es, "tried to add a string to %s AwkArray %s",
  196.         array->ival ? "AWK_INT" :
  197.         (array->fval ? "AWK_FLOAT" : "AWK_INDEX"),
  198.         array->name);
  199.     error (NOTFATAL, es);
  200.     return;
  201.     }
  202. #endif
  203.     array->string[awkAddIndex (array, key)] = (char *)p;
  204. }
  205.  
  206. void awkAddString (AwkArray *array, char *key, char *s) {
  207. #ifdef CAREFUL
  208.     if (awkinited == 0)
  209.     error (AWKFATAL, "awkAddString called prior to awkInit");
  210.     if (array == 0)
  211.     error (AWKFATAL,"awkAddString: tried to access an uninitialized array");
  212.     if (array->string == 0) {
  213.     sprintf (es, "tried to add a string to %s AwkArray %s",
  214.         array->ival ? "AWK_INT" :
  215.         (array->fval ? "AWK_FLOAT" : "AWK_INDEX"),
  216.         array->name);
  217.     error (NOTFATAL, es);
  218.     return;
  219.     }
  220. #endif
  221.     array->string[awkAddIndex (array, key)] = newstring (s);
  222. }
  223.  
  224. AwkArray *awkNewArray (char *name, int type) {
  225.     /* create a new Array.  call newarray to add storage tables */
  226.     AwkArray *array;
  227. #ifdef CAREFUL
  228.     if (awkinited == 0)
  229.     error (AWKFATAL, "awkNewArray called prior to awkInit");
  230. #endif
  231.     if ((array = (AwkArray*)malloc (sizeof (AwkArray))) == 0) {
  232.     sprintf (es, "malloc failed for array %s", name);
  233.     error (AWKFATAL, es);
  234.     }
  235.     array->max = INITIALSIZE;
  236.     array->remain = REMAIN (array->max);
  237.     array->index = 1;
  238.     array->name = newstring (name);
  239.     array->ival = 0;
  240.     array->fval = 0;
  241.     array->string = 0;
  242.     switch (type) {
  243.     case AWK_INDEX: break;
  244.     case AWK_INT: array->ival = (int*)1; break;
  245.     case AWK_FLOAT: array->fval = (float*)1; break;
  246.     case AWK_STRING:
  247.     case AWK_POINTER: array->string = (char**)1; break;
  248.     default:
  249.         sprintf (es, "array %s has invalid type", name);
  250.         error (AWKFATAL, es);
  251.         break;
  252.     }
  253. #ifdef METER
  254.     array->access = 0;
  255.     array->search = 0;
  256.     if (arraycount >= MAXARRAY)
  257.     error (AWKFATAL, "too many arrays");
  258.     arraylist[arraycount++] = array;
  259.     storage += sizeof (AwkArray);
  260. #endif
  261.     return newarray (array);
  262. }
  263.  
  264. void awkExit (void) {
  265.     if (STAT)
  266.     _awk_statall ();
  267.     /* XXX - should free all data structures */
  268. }
  269.  
  270. void awkFile (char *name) {
  271.     ARGC = 0;
  272.     awkclose ();
  273.     awkopen (name);
  274. }
  275.  
  276. void awkInit (int argc, char **argv) {
  277.     /* to be called first */
  278.     int i;
  279.     ARGC = argc;
  280.     ARGV = argv;
  281.     STAT = DEBUG = FALSE;
  282.     awkNL = 0;
  283.     awkNR = 0;
  284.     awkFS = ' ';
  285.     awkRS = '\n';
  286.     awkARG[0] = line;
  287.     for (i=1; i<argc; i++) {
  288.     if (awkStrSame (argv[i], "-DEBUG")) {
  289.         DEBUG = TRUE;
  290.         fprintf (stderr, "awk: version %s, %s\n", VERSION, DATE);
  291.         fprintf (stderr, "awk: debug mode enabled\n");
  292.         argv[i][0] = 0;
  293.     }
  294.     else if (awkStrSame (argv[i], "-STAT")) {
  295.         STAT = TRUE;
  296.         fprintf (stderr, "awk: version %s, %s\n", VERSION, DATE);
  297.         fprintf (stderr, "awk: stat mode enabled\n");
  298.         argv[i][0] = 0;
  299.     }
  300.     else if (awkStrIndex (argv[i], "-F") == 1) {
  301.         awkFS = argv[i][2];
  302.         argv[i][0] = 0;
  303.     }
  304.     }
  305.     awkopennext();
  306.  
  307.     for (i=0; i<128; i++)
  308.     hashval[i] = rand ();
  309. #ifdef METER
  310.     access = search = storage = arraycount = 0;
  311. #endif
  312.     awkinited = 1;
  313. }
  314.  
  315. int awkStrSame (register char *s1, register char *s2) {
  316.     while (*s1 == *s2++)
  317.     if (*s1++ == 0)
  318.         return TRUE;
  319.     return FALSE;
  320. }
  321.  
  322. void awkFirstKey (AwkArray *array) {
  323.     /* prepare for awkNextKey() calls */
  324.     array->index = 1;
  325. }
  326.  
  327. float awkGetFloat (AwkArray *array, char *key) {
  328. #ifdef CAREFUL
  329.     if (awkinited == 0)
  330.     error (AWKFATAL, "awkGetFloat called prior to awkInit");
  331.     if (array == 0)
  332.     error (AWKFATAL, "awkGetFloat: tried to access an uninitialized array");
  333.     if (array->fval == 0) {
  334.     sprintf (es, "tried to access a float in %s AwkArray %s",
  335.         array->ival ? "AWK_INT" :
  336.         (array->string ? "AWK_STRING" : "AWK_INDEX"),
  337.         array->name);
  338.     error (NOTFATAL, es);
  339.     return;
  340.     }
  341. #endif
  342.     return array->fval[awkGetIndex (array, key)];
  343. }
  344.  
  345. int awkGetIndex (register AwkArray *array, register char *key) {
  346.     /* return the index of the given key, or zero if no index corresponds */
  347.     register index;
  348.     register maxindex;
  349.     index = hash (array, key);
  350.     maxindex = array->max - 1;
  351. #ifdef METER
  352.     array->access += 1;
  353.     access += 1;
  354. #endif
  355.     while (TRUE) {
  356.     if (array->key[index]) {
  357.         if (awkStrSame (key, array->key[index]))
  358.         return index;
  359.         else {
  360. #ifdef METER
  361.         array->search += 1;
  362.         search += 1;
  363. #endif
  364.         if (index == maxindex)
  365.             index = 0;
  366.         else
  367.             index += 1;
  368.         }
  369.     }
  370.     else
  371.         return 0;
  372.     }
  373. }
  374.  
  375. int awkGetInt (AwkArray *array, char *key) {
  376. #ifdef CAREFUL
  377.     if (awkinited == 0)
  378.     error (AWKFATAL, "awkGetInt called prior to awkInit");
  379.     if (array == 0)
  380.     error (AWKFATAL, "awkGetInt: tried to access an uninitialized array");
  381.     if (array->ival == 0) {
  382.     sprintf (es, "tried to access an integer in %s AwkArray %s",
  383.         array->fval ? "AWK_FLOAT" :
  384.         (array->string ? "AWK_STRING" : "AWK_INDEX"),
  385.         array->name);
  386.     error (NOTFATAL, es);
  387.     return;
  388.     }
  389. #endif
  390.     return array->ival[awkGetIndex (array, key)];
  391. }
  392.  
  393. void *awkGetPointer (AwkArray *array, char *key) {
  394.     register i;
  395. #ifdef CAREFUL
  396.     if (awkinited == 0)
  397.     error (AWKFATAL, "awkGetPointer called prior to awkInit");
  398.     if (array == 0)
  399.     error (AWKFATAL,
  400.         "awkGetPointer: tried to access an uninitialized array");
  401.     if (array->string == 0) {
  402.     sprintf (es, "tried to access a pointer in %s AwkArray %s",
  403.         array->ival ? "AWK_INT" :
  404.         (array->fval ? "AWK_FLOAT" : "AWK_INDEX"),
  405.         array->name);
  406.     error (NOTFATAL, es);
  407.     return 0;
  408.     }
  409. #endif
  410.     i = awkGetIndex (array, key);
  411.     if (i)
  412.     return (void *)(array->string[i]);
  413.     else
  414.     return 0;
  415. }
  416.  
  417. void awkGetString (AwkArray *array, char *key, char *s) {
  418. #ifdef CAREFUL
  419.     if (awkinited == 0)
  420.     error (AWKFATAL, "awkGetString called prior to awkInit");
  421.     if (array == 0)
  422.     error (AWKFATAL,
  423.         "awkGetString: tried to access an uninitialized array");
  424.     if (array->string == 0) {
  425.     sprintf (es, "tried to access a string in %s AwkArray %s",
  426.         array->ival ? "AWK_INT" :
  427.         (array->fval ? "AWK_FLOAT" : "AWK_INDEX"),
  428.         array->name);
  429.     error (NOTFATAL, es);
  430.     return;
  431.     }
  432. #endif
  433.     strcpy (s, array->string[awkGetIndex (array, key)]);
  434. }
  435.  
  436. int awkNextKey (AwkArray *array, char *key) {
  437.     /* returns the 'next' key in the array - call awkFirstKey() to initialize */
  438.     register index, max;
  439.     for (index=array->index, max=array->max; index < max; index++) {
  440.     if (array->key[index]) {
  441.         strcpy (key, array->key[index]);
  442.         array->index = index + 1;
  443.         return TRUE;
  444.     }
  445.     }
  446.     return FALSE;
  447. }
  448.  
  449. int awkNextRecord (void) {
  450.     /* read and parse the next input line - return FALSE if no lines left */
  451.  
  452.     register c;
  453.     register i;
  454.     register space;
  455.  
  456. #ifdef CAREFUL
  457.     if (awkinited == 0)
  458.     error (AWKFATAL, "awkNextRecord called prior to awkInit");
  459. #endif
  460.     awkNF = 0;
  461.     i = 0;
  462.     space = TRUE;
  463.     while (1) {
  464.     c = getc (infile);
  465.     line[i] = c;
  466.     if (c == '\t')
  467.         c = ' ';
  468.     if (c == EOF) {
  469.         if (i) {
  470.         break;
  471.         }
  472.         awkclose();
  473.         if (awkopennext()) {
  474.         space = TRUE;
  475.         continue;
  476.         }
  477.         else {
  478.         return FALSE;
  479.         }
  480.     }
  481.     else if (c == awkRS) {
  482.         break;
  483.     }
  484.     else if (c == awkFS) {
  485.         if (!space) {
  486.         space = TRUE;
  487.         }
  488.         if (i > MAXARGLEN)
  489.         error (AWKFATAL, "record too long");
  490.         args[i++] = '\0';
  491.     }
  492.     else {
  493.         if (space) {
  494.         space = FALSE;
  495.         awkNF += 1;
  496.         if (awkNF >= MAXARG)
  497.             error (AWKFATAL, "too many fields");
  498.         awkARG[awkNF] = &args[i];
  499.         }
  500.         if (i > MAXARGLEN)
  501.         error (AWKFATAL, "record too long");
  502.         args[i++] = c;
  503.     }
  504.     }
  505.     args[i] = '\0';
  506.     line[i] = '\0';
  507.     if (DEBUG)
  508.     fprintf (stderr, "%s %d: %s\n", awkFILENAME, awkNL, awkARG[0]);
  509.     awkNR += 1;
  510.     awkNL += 1;
  511.     return TRUE;
  512. }
  513.  
  514. int awkStrIndex (register char *s1, register char *s2) {
  515.     /*
  516.      *    Return the location in s1 at which s2 begins.  Return 0 if s2 is
  517.      *    not a substring of s1.  First location in s1 is 1, not 0.
  518.      */
  519.     register i;
  520.     register char *s, *t;
  521.     register maxi;
  522.     for (maxi=0, s=s1; *s++;)
  523.     maxi += 1;
  524.     for (t=s2; *t++;)
  525.     maxi -= 1;
  526.     for (i=0; i <= maxi; i++) {
  527.     for (s=s1+i, t=s2; ;)    {
  528.         if (*t == '\0')
  529.         return (i+1);
  530.         else if (*s++ != *t++)
  531.         break;
  532.     }
  533.     }
  534.     return 0;
  535. }
  536.  
  537. void awkSubStr (register char *s1, register char *s2, register m, register n) {
  538.     /*
  539.      *    Copy the string starting at the mth character in s2 to s1.
  540.      *    Limit the length of this string to n characters.  The index
  541.      *    of the first character in s1 is 1, not 0.
  542.      */
  543.     for (s2+=(m-1); n--;)
  544.     if (!(*s1++ = *s2++))
  545.         break;
  546.     *s1 = '\0';
  547. }
  548.  
  549. /*
  550.  * Internal procedures and functions
  551.  */
  552.  
  553. static void awkopen (char *s) {
  554.     awkNL = 0;
  555.     if (awkStrSame (s, "-")) {
  556.     strcpy (awkFILENAME, "stdin");
  557.     infile = stdin;
  558.     }
  559.     else {
  560.     strcpy (awkFILENAME, s);
  561.     if ((infile = fopen (s, "r")) == NULL)
  562.         error (AWKFATAL, "cannot open");
  563.     }
  564.     filecount += 1;
  565. }
  566.  
  567. static int awkopennext(void) {
  568.     /* open the next input file */
  569.     /* ignore null argv fields */
  570.     /* returns TRUE if a new file was opened, FALSE otherwise */
  571.     static int i = 1;
  572.  
  573.     /* find the next non-null argument and open it */
  574.     for (; i < ARGC;) {
  575.     if (ARGV[i][0]) {
  576.         awkopen (ARGV[i]);
  577.         i += 1;
  578.         return TRUE;
  579.     }
  580.     else
  581.         i += 1;
  582.     }
  583.  
  584.     /* if no non-null fields, and no files have been opened, open stdin */
  585.     if (filecount == 0) {
  586.     awkopen("-");
  587.     return TRUE;
  588.     }
  589.     return FALSE;
  590. }
  591.  
  592. static void awkclose (void) {
  593.     if (infile && infile != stdin) {
  594.     fclose (infile);
  595.     strcpy (awkFILENAME, "END");
  596.     }
  597. }
  598.  
  599. static void error (int class, char *s) {
  600.     /* print an error message, exit if fatal */
  601.     fprintf (stderr, "awk: file <%s> line %d: %s.", awkFILENAME, awkNL, s);
  602.     if (class == AWKFATAL) {
  603.     fprintf (stderr, " exit.\n\007");
  604.     exit (1);
  605.     }
  606.     else
  607.     fprintf (stderr, "\n");
  608. }
  609.  
  610. static void expandarray (AwkArray *array) {
  611.     AwkArray temp;
  612.     char key[MAXKEYLEN+2];
  613.     /* copy the array information to a temporary array */
  614.     temp.max = array->max;
  615.     temp.remain = array->remain;
  616.     temp.index = 1;
  617.     temp.name = array->name;
  618.     temp.key = array->key;
  619.     temp.ival = array->ival;
  620.     temp.fval = array->fval;
  621.     temp.string = array->string;
  622.     /* double the data structure size of the original array */
  623.     array->max = 2 * array->max;
  624.     array->remain = REMAIN (array->max);
  625.     newarray (array);
  626.     /* copy the data from the temp array to the new array */
  627.     if (array->ival) {
  628.     for (awkFirstKey(&temp); awkNextKey(&temp,key);)
  629.         awkAddInt (array, key, awkGetInt (&temp,key));
  630.     free (temp.ival);
  631.     }
  632.     else if (array->fval) {
  633.     for (awkFirstKey(&temp); awkNextKey(&temp,key);)
  634.         awkAddFloat (array, key, awkGetFloat (&temp,key));
  635.     free (temp.fval);
  636.     }
  637.     else if (array->string) {
  638.     for (awkFirstKey(&temp); awkNextKey(&temp,key);)
  639.         awkAddPointer (array, key, awkGetPointer (&temp,key));
  640.     free (temp.string);
  641.     }
  642.     free (temp.key);
  643. }
  644.  
  645. static int hash (AwkArray *array, register char *key) {
  646.     /* must return zero for the null string */
  647.     register int *val;
  648.     register i;
  649.     char *s;
  650.     val = hashval;
  651.     s = key;
  652.     for (i=0; *key;)
  653.     i += val[*key++];
  654.     return (array->max * (i&0x3FFF)) >> 14;
  655. }
  656.  
  657. static AwkArray *newarray (AwkArray *array) {
  658.     /* malloc and initialize memory for key pointers and data (pointers) */
  659.     register i;
  660.  
  661.     /* allocate and initialize the key pointers */
  662.     if ((array->key = (char**)(malloc (array->max * sizeof (char*)))) == 0) {
  663.     sprintf (es, "malloc failed for array %s", array->name);
  664.     error (AWKFATAL, es);
  665.     }
  666.     for (i=0; i < array->max; i++)
  667.     array->key[i] = 0;
  668. #ifdef METER
  669.     storage += array->max * sizeof (char*);
  670. #endif
  671.  
  672.     /* allocate data space if required */
  673.     if (array->ival) {
  674.     if ((array->ival = (int*)malloc (array->max * sizeof (int))) == 0) {
  675.         sprintf (es, "malloc failed for array %s", array->name);
  676.         error (AWKFATAL, es);
  677.     }
  678.     awkAddInt (array, "", 0);
  679. #ifdef METER
  680.     storage += array->max * sizeof (int);
  681. #endif
  682.     }
  683.     else if (array->fval) {
  684.     if ((array->fval = (float*)malloc (array->max * sizeof (float))) == 0) {
  685.         sprintf (es, "malloc failed for array %s", array->name);
  686.         error (AWKFATAL, es);
  687.     }
  688.     awkAddFloat (array, "", 0.0);
  689. #ifdef METER
  690.     storage += array->max * sizeof (float);
  691. #endif
  692.     }
  693.     else if (array->string) {
  694.     if ((array->string = (char**)malloc (array->max * sizeof (char*)))==0){
  695.         sprintf (es, "malloc failed for array %s", array->name);
  696.         error (AWKFATAL, es);
  697.     }
  698.     awkAddString (array, "", "");
  699. #ifdef METER
  700.     storage += array->max * sizeof (char*);
  701. #endif
  702.     }
  703.     return array;
  704. }
  705.  
  706. #define MALLOCSIZE    0x1000
  707.  
  708. static char *newstring (char *s) {
  709.     /* alloc a new string */
  710.     static int avail = 0;
  711.     static char *mem;
  712.     register len;
  713.     register char *t;
  714.  
  715.     for (t=s, len=0; *t++;)
  716.     ;
  717.     len = t - s;
  718.     if (len > avail) {
  719.     if ((mem = (char*)malloc (MALLOCSIZE)) == 0) {
  720.         sprintf (es, "malloc failed for string %s", s);
  721.         error (AWKFATAL, es);
  722.     }
  723.     avail = MALLOCSIZE;
  724. #ifdef METER
  725.     storage += MALLOCSIZE;
  726. #endif
  727.     }
  728.     for (t=mem; *t++ = *s++;)
  729.     ;
  730.     t = mem;
  731.     mem += len;
  732.     avail -= len;
  733.     return t;
  734. }
  735.  
  736. /*
  737.  * Diagnostic procedures and functions
  738.  */
  739.  
  740. void _awk_seearray (AwkArray *array) {
  741.     register index;
  742.     printf ("seearray: array address %x\n", array);
  743.     fflush (stdout);
  744.     printf ("array %s:\n  max %d\n  remain %d\n", array->name,
  745.     array->max, array->remain);
  746.     fflush (stdout);
  747.     for (index=0; index < array->max; index++) {
  748.     printf ("  %2d: ", index);
  749.     fflush (stdout);
  750.     if (array->key[index]) {
  751.         printf ("<%s> ", array->key[index]);
  752.         fflush (stdout);
  753.         if (array->ival)
  754.         printf ("%d ", array->ival[index]);
  755.         if (array->fval)
  756.         printf ("%f ", array->fval[index]);
  757.         if (array->string) {
  758.         if (array->string[index])
  759.             printf ("<%s> ", array->string[index]);
  760.         else
  761.             printf ("<null pointer>");
  762.         }
  763.         fflush (stdout);
  764.         }
  765.     printf ("\n");
  766.     }
  767.     }
  768.  
  769. void _awk_statall (void) {
  770.     int i;
  771.     AwkArray *array;
  772. #ifdef METER
  773.     fprintf (stderr, "STATISTICS:\n");
  774.     for (i=0; i<arraycount; i++) {
  775.     array = (AwkArray*)arraylist[i];
  776.     fprintf (stderr, "%16s: %5d locations, ", array->name, array->max);
  777.     fprintf (stderr,"%8d accesses, %5.2f searches/access\n",
  778.         array->access, (float)(array->search) / (float)(array->access));
  779.     }
  780.     fprintf (stderr, "%8d total accessses\n", access);
  781.     fprintf (stderr, "%8d total searches\n", search);
  782.     fprintf (stderr, " %7.2f searches/access\n",(float)search/(float)access);
  783. #else
  784.     fprintf (stderr, "WARNING: no statistics kept!\n");
  785. #endif
  786. }
  787.